﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Infrastructure.Model;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Infrastructure.Model.ApiResult;

namespace Infrastructure.Helper
{
    /// <summary>
    /// RESTful HTTP 请求辅助类
    /// 提供同步/异步的GET/POST请求能力，支持Token验证和自定义请求头
    /// </summary>
    /// <remarks>
    /// 主要特性：
    /// - 自动处理请求/响应序列化
    /// - 支持多种认证方式
    /// - 统一的错误处理机制
    /// - 支持同步和异步操作
    /// 
    /// 注意：WebClient已过时，建议升级到HttpClient版本
    /// </remarks>
    internal class RestfulHelper
    {
        /// <summary>
        /// 认证令牌的请求头名称（默认为空）
        /// 示例：Authorization
        /// </summary>
        public string TokenHeaderName { get; set; }

        /// <summary>
        /// 默认认证令牌值（当未显式指定token时使用）
        /// </summary>
        public string DefaultToken { get; set; }

        /// <summary>
        /// 自定义请求头集合
        /// Key为HeaderName枚举值，Value为对应的头值
        /// </summary>
        public Dictionary<HeaderName, string> Headers { get; set; }

        #region 构造函数
        /// <summary>
        /// 默认空构造函数
        /// </summary>
        public RestfulHelper() { }

        /// <summary>
        /// 指定认证头名称的构造函数
        /// </summary>
        /// <param name="tokenHeaderName">如：X-Auth-Token</param>
        public RestfulHelper(string tokenHeaderName)
        {
            TokenHeaderName = tokenHeaderName;
        }

        /// <summary>
        /// 指定自定义请求头的构造函数
        /// </summary>
        /// <param name="headers">预定义的请求头集合</param>
        public RestfulHelper(Dictionary<HeaderName, string> headers)
        {
            Headers = headers;
        }

        /// <summary>
        /// 完整认证参数的构造函数
        /// </summary>
        /// <param name="tokenHeaderName">认证头名称</param>
        /// <param name="defaultToken">默认令牌值</param>
        public RestfulHelper(string tokenHeaderName, string defaultToken)
        {
            TokenHeaderName = tokenHeaderName;
            DefaultToken = defaultToken;
        }
        #endregion

        #region GET 方法
        /// <summary>
        /// 执行GET请求（使用默认令牌）
        /// </summary>
        /// <param name="apiUrl">API端点地址</param>
        /// <param name="queryParams">查询参数集合</param>
        /// <returns>封装后的API结果</returns>
        public ApiResult Get(string apiUrl, Hashtable queryParams = null)
        {
            return Get(apiUrl, queryParams, DefaultToken);
        }

        /// <summary>
        /// 内部GET请求实现
        /// </summary>
        /// <param name="apiUrl">API端点地址</param>
        /// <param name="queryParams">查询参数集合</param>
        /// <param name="token">认证令牌</param>
        /// <returns>API结果对象</returns>
        private ApiResult Get(string apiUrl, Hashtable queryParams, string token)
        {
            try
            {
                using (var webClient = CreateWebClient(token))
                {
                    var formattedUrl = FormatUrl(apiUrl, queryParams);
                    var response = webClient.DownloadString(formattedUrl);
                    return JsonConvert.DeserializeObject<ApiResult>(response);
                }
            }
            catch (JsonException ex)
            {
                return ApiResult.Error($"JSON转换错误: {ex.Message}");
            }
            catch (Exception e)
            {
                return WhenError(e);
            }
        }
        #endregion

        #region POST 方法
        // 方法重载说明：
        // - 提供多种参数组合：无参/带查询参数/带请求体/全参数
        // - 所有重载最终调用私有Post方法实现

        /// <summary>
        /// 执行基本POST请求
        /// </summary>
        public ApiResult Post(string apiUrl) => Post(apiUrl, null, null, DefaultToken);

        /// <summary>
        /// 带查询参数的POST请求
        /// </summary>
        public ApiResult Post(string apiUrl, Hashtable queryParams) => Post(apiUrl, queryParams, null, DefaultToken);

        /// <summary>
        /// 带请求体的POST请求
        /// </summary>
        public ApiResult Post(string apiUrl, object body) => Post(apiUrl, null, body, DefaultToken);

        /// <summary>
        /// 完整参数的POST请求
        /// </summary>
        public ApiResult Post(string apiUrl, Hashtable queryParams, object body) => Post(apiUrl, queryParams, body, DefaultToken);

        /// <summary>
        /// POST请求核心实现
        /// </summary>
        private ApiResult Post(string apiUrl, Hashtable queryParams, object body, string token)
        {
            try
            {
                var requestBody = body != null ? JsonConvert.SerializeObject(body) : "";
                using (var webClient = CreateWebClient(token))
                {
                    var formattedUrl = FormatUrl(apiUrl, queryParams);
                    var response = webClient.UploadString(formattedUrl, "POST", requestBody);
                    return JsonConvert.DeserializeObject<ApiResult>(response);
                }
            }
            catch (JsonException ex)
            {
                return ApiResult.Error($"JSON转换错误: {ex.Message}");
            }
            catch (Exception e)
            {
                return WhenError(e);
            }
        }
        #endregion

        #region 异步方法
        /// <summary>
        /// 异步POST请求（使用JArray作为请求体）
        /// 注意：当前实现存在资源释放时机问题
        /// </summary>
        public void PostAsync(string apiUrl, Hashtable queryParams, JArray body)
            => PostAsync(apiUrl, queryParams, body, DefaultToken);

        /// <summary>
        /// 异步POST请求实现
        /// </summary>
        public void PostAsync(string apiUrl, Hashtable queryParams, JArray body, string token)
        {
            var webClient = CreateWebClient(token);
            var formattedUrl = FormatUrl(apiUrl, queryParams);
            try
            {
                var data = Encoding.UTF8.GetBytes(body.ToString(Formatting.None));
                webClient.UploadDataAsync(new Uri(formattedUrl), "POST", data);
            }
            finally
            {
                webClient.Dispose(); // 注意：可能在上传完成前释放资源
            }
        }
        #endregion

        #region 辅助方法
        /// <summary>
        /// 创建配置好的WebClient实例
        /// </summary>
        /// <param name="token">当前请求使用的认证令牌</param>
        /// <returns>预配置的WebClient实例</returns>
        private WebClient CreateWebClient(string token)
        {
            var client = new WebClient();

            // 设置默认头
            client.Headers[HttpRequestHeader.Accept] = "application/json";
            client.Headers[HttpRequestHeader.ContentType] = "application/json";

            // 添加认证头
            if (!string.IsNullOrEmpty(TokenHeaderName) && !string.IsNullOrEmpty(token))
            {
                client.Headers.Add(TokenHeaderName, token);
            }

            // 添加自定义头
            foreach (var header in Headers ?? new Dictionary<HeaderName, string>())
            {
                client.Headers.Add(header.Key.ToString(), header.Value);
            }

            client.Encoding = Encoding.UTF8;
            return client;
        }

        /// <summary>
        /// 构建带查询参数的完整URL
        /// 注意：未进行URL编码，参数值包含特殊字符时需要预处理
        /// </summary>
        private string FormatUrl(string apiUrl, Hashtable queryParams)
        {
            if (queryParams == null || queryParams.Count == 0)
                return apiUrl;

            var parameters = new List<string>();
            foreach (DictionaryEntry param in queryParams)
            {
                parameters.Add($"{param.Key}={param.Value}");
            }
            return $"{apiUrl}?{string.Join("&", parameters)}";
        }

        /// <summary>
        /// 统一错误处理
        /// </summary>
        private ApiResult WhenError(Exception e)
        {
            if (e is WebException webEx)
            {
                using (var response = webEx.Response as HttpWebResponse)
                {
                    if (response != null)
                    {
                        var statusCode = (int)response.StatusCode;
                        using (var reader = new StreamReader(response.GetResponseStream()))
                        {
                            var content = reader.ReadToEnd();
                            return ApiResult.Error($"HTTP错误 {statusCode}: {content}");
                        }
                    }
                }
                return ApiResult.Error("网络请求失败: " + webEx.Message);
            }
            return ApiResult.Error("系统错误: " + e.Message);
        }
        #endregion
    }
}
